package com.ruoyi.common.utils.bean;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

/**
* @Description list<Bean>拷贝工具类
* @ClassName BeanCopyUtil
* @Author Miss You BUG
* @Date 2020/6/19 14:24
* @Version 1.0
* <p>
* 版权声明：本文为CSDN博主「百块富翁-missyouBUG-renkaijiang」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
* 原文链接：https://blog.csdn.net/lingyancangqiong/article/details/118539165
*/
public class BeanCpUtils extends BeanUtils {

   /**
    * <p>对象数据的拷贝</p>
    *
    * @param sources 数据源
    * @param target  目标参数类型(eg: UserVo:new)
    * @return
    * @author Miss You BUG
    * @Date 2020/6/19 15:20
    */
   public static <S, T> T copyProperties(S sources, Supplier<T> target) {
       T t = target.get();
       copyProperties(sources, t);
       return t;
   }

   /**
    * <p>带回调参数的对象数据的拷贝</p>
    *
    * @param sources 数据源
    * @param target  目标参数类型(eg: BeanCopyUtil.copyProperties(user,UserVO:: new, (userDo,userVo) ->{
    *                *                 userVo.setSex("1")})
    * @return
    * @author Miss You BUG
    * @Date 2020/6/19 15:20
    */
   public static <S, T> T copyProperties(S sources, Supplier<T> target, IBeanCpCallBack<S, T> callBack) {
       T t = target.get();
       copyProperties(sources, t);
       if (callBack != null) {
           callBack.callBack(sources, t);
       }
       return t;
   }
   /**
    * 拷贝不为空的字段
    * 使用场景：只想把 sources中有值的拷贝到target中，而不把target对应sources中没有值的赋值为null
    * 使用 BeanUtils.copyProperties();会全量拷贝，包括null
    *
    * @param sources 数据源
    * @param target  目标
    * @param <S>     数据源泛型
    * @param <T>     目标泛型
    * @return 目标数据
    */
   public static <S, T> T copyNotEmptyProperties(S sources, T target) {
       copyProperties(sources, target, getNullPropertyNames(sources));
       return target;
   }

   /**
    * 拷贝不为空的字段:带回调参数
    * 使用场景：只想把 sources中有值的拷贝到target中，而不把target对应sources中没有值的赋值为null
    * 使用 BeanUtils.copyProperties();会全量拷贝，包括null
    *
    * @param sources 数据源
    * @param target  目标
    * @param <S>     数据源泛型
    * @param <T>     目标泛型
    * @return 目标数据
    */
   public static <S, T> T copyNotEmptyProperties(S sources, T target, IBeanCpCallBack<S, T> callBack) {
       copyProperties(sources, target, getNullPropertyNames(sources));
       if (callBack != null) {
           callBack.callBack(sources, target);
       }
       return target;
   }

   /**
    * <p>集合数据的拷贝</p>
    *
    * @param sources 数据源
    * @param target  目标参数类型(eg: UserVo:new)
    * @return
    * @author Miss You BUG
    * @Date 2020/6/19 15:06
    */
   public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
       return copyListProperties(sources, target, null);
   }

   /**
    * <p>带回调参数的集合数据的拷贝</p>
    *
    * @param sources  数据源类
    * @param target   目标类::new (eg: UserVO::new)
    * @param callBack 回调函数 eg: BeanCopyUtil.copyListProperties(userLiset,UserVO:: new, (userDo,userVo) ->{
    *                 userVo.setSex("1");
    *                 userVO.setName(userDo.getUserName());
    *                 })
    * @return List<T> List<Bean>
    * @author Miss You BUG
    * @Date 2020/6/19 15:09
    */
   public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, IBeanCpCallBack<S, T> callBack) {
       List<T> list = new ArrayList<>(sources.size());
       for (S source : sources) {
           T t = target.get();
           copyProperties(source, t);
           list.add(t);
           if (callBack != null) {
               callBack.callBack(source, t);
           }
       }
       return list;
   }

//   public static <S, T> List<T> copyListProperties(List<S> sources, T target, IBeanCpCallBack<S, T> callBack) {
//       List<T> list = new ArrayList<>(sources.size());
//       for (S source : sources) {
//           T t = target.getClass().newInstance();
//           copyProperties(source, t);
//           list.add(t);
//           if (callBack != null) {
//               callBack.callBack(source, t);
//           }
//       }
//       return list;
//   }

   /**
    * 获取为空的字段
    */
   private static String[] getNullPropertyNames(Object source) {
       BeanWrapper src = new BeanWrapperImpl(source);
       PropertyDescriptor[] pds = src.getPropertyDescriptors();
       Set<String> emptyNames = new HashSet<>();
       for (PropertyDescriptor pd : pds) {
           Object srcValue = src.getPropertyValue(pd.getName());
           if (srcValue == null)
               emptyNames.add(pd.getName());
       }
       return emptyNames.toArray(new String[emptyNames.size()]);
   }
   
   /**
	https://blog.csdn.net/lingyancangqiong/article/details/118539165

	List<UserVO> userVOS1 = BeanCopyUtil.copyListProperties(userDoList1, UserVO::new);
       System.out.println("copy list:" + userVOS1);

       List<UserVO> userVOS2 = BeanCopyUtil.copyListProperties(userDoList1, UserVO::new,
               (userDo, userVo) -> {
                   userVo.setAddressStr(userDo.getAddress());
                   userVo.setIsAdult(userDo.getIsAdult()==0?"未成年":"已成年");
               });
       System.out.println("copy list 带回调:" + userVOS2);
    */
}
